export function sum(iterator) {
  const array = this;
  let sum = 0;
  if (iterator) {
    array.forEach((a, i) => {
      sum += iterator.call(a, a, i);
    });
  } else {
    array.forEach(a => {
      if (typeof a == 'number') sum += a;
    });
  }
  return sum;
}

export function max(iterator) {
  var arr = orderBy.call(this, iterator, true);
  if (arr.length) {
    return arr[0];
  }
  return null;
}

export function min(iterator) {
  var arr = orderBy.call(this, iterator, false);
  if (arr.length) {
    return arr[0];
  }
  return null;
}

export function orderBy(iterator, isdesc = false) {
  const arrays = this;
  let sort = isdesc ? -1 : 1;
  if (iterator) {
    var arrays2 = new Array();
    arrays.forEach((a, i) => {
      arrays2.push({
        v: iterator(a),
        i
      });
    });
    arrays2 = arrays2.sort((a, b) => {
      if (a.v > b.v) return sort;
      if (a.v < b.v) return -1 * sort;
      return 0;
    });
    return arrays2.map(a => arrays[a.i]);
  } else {
    return arrays.sort((a, b) => {
      if (a > b) return sort;
      if (a < b) return -1 * sort;
      return 0;
    });
  }
}

/**
 * 交集
 * @param {Array} arrays
 * @param {Function} iterator
 */
export function intersectBy(arrays, iterator) {
  const intersect = [];
  const source = this.map(item => (iterator ? iterator(item) : item));
  arrays.forEach(item => {
    const value = iterator ? iterator(item) : item;
    if (source.indexOf(value) >= 0) {
      intersect.push(item);
    }
  });
  return intersect;
}

/**
 * 并集
 * @param {Array} arrays
 * @param {Function} iterator
 */
export function unionBy(arrays, iterator) {
  const unions = [...this];
  const source = this.map(item => (iterator ? iterator(item) : item));
  arrays.forEach(item => {
    const value = iterator ? iterator(item) : item;
    if (source.indexOf(value) < 0) {
      unions.push(item);
    }
  });
  return unions;
}

/**
 * 差集
 * @param {Array} arrays
 * @param {Function} iterator
 * @returns
 */
export function exceptBy(arrays, iterator) {
  const except = [];
  const source = arrays.map(item => (iterator ? iterator(item) : item));
  this.forEach(item => {
    const value = iterator ? iterator(item) : item;
    if (source.indexOf(value) < 0) {
      except.push(item);
    }
  });
  return except;
}

/**
 * 去重
 * @param {Function} iterator
 * @returns
 */
export function distinctBy(iterator) {
  const arrays = this;
  const distinct = [];
  const source = arrays.map(item => (iterator ? iterator(item) : item));
  source.forEach((item, i) => {
    for (let j = 0; j < i; j++) {
      const value = source[j];
      if (value == item) {
        return;
      }
    }
    distinct.push(arrays[i]);
  });
  return distinct;
}

export function groupBy(groupkey, valueFunc) {
  const arrays = this;
  const result = {};
  arrays.forEach(item => {
    const key = groupkey(item);
    if (!result[key]) {
      result[key] = [];
    }
    if (valueFunc) {
      item = valueFunc(item);
    }
    result[key].push(item);
  });
  return result;
}

export function toMap(keyFunc, valueFunc) {
  const arrays = this;
  let result = {};
  if (valueFunc) {
    arrays.forEach(a => {
      result[keyFunc(a)] = valueFunc(a);
    });
  } else {
    arrays.forEach(a => {
      result[keyFunc(a)] = a;
    });
  }
  return result;
}

export function flag(iterator) {
  const arrays = this;
  let result = 0;
  for (let i = 0; i < arrays.length; i++) {
    const item = iterator ? iterator(arrays[i]) : arrays[i];
    result |= item;
  }
  return result;
}

export function _formFlag(value) {
  const result = [];
  let b = 1;
  while (value >= b) {
    if ((b & value) == b) {
      result.push(b);
    }
    b <<= 1;
  }
  return result;
}
